#include "Str.h"

#include <stdio.h> //for malloc & friends
#include <stdlib.h>//for malloc & friends

int Str::charSize(const char* str)
{
	int i=0;
	while (str[i]!='\0'){i++;}
	return i;
}
char* Str::getPart(int from,int to,char* str)
{
	for (int i=from;i<to;i++)
	{str[i-from]=chr[i];}
	str[to]='\0';
	return str;
}
int Str::pow(int a,int b)
{
	int res=1;
	for (int i=0;i<b;i++)
	{res*=a;}
	return res;
}
Str& Str::toI(int num,Str& str)
{
	str.clear();
	if (num==0){str="0";return str;}
	if (num<0){str<<"-";num*=-1;}
	int sz=1;
	int temp=num;
	while (temp>0){temp/=10;sz++;}
	for (int i=sz-1;i>0;i--)
	{
		int nn;
		nn=num/pow(10,i-1);
		str<<(char)(nn+int('0'));
		num%=pow(10,i-1);
	}
	return str;
}
Str& Str::toD(double num,Str& str)
{
	if (num<0.0){str="-";num*=-1.0;}else{str.clear();}
	str<<(int)num;
	num-=double((int)num);
	int place=10;
	while (1)
	{
		if (place>=99999999){break;}
		if (place==10){str<<".";}
		int t=0;
		t=int(num*place);
		double terminator=(num*place)-double(t);
		if (terminator<0.000000001 && t%10==0)
		{
			if (place==10){str<<"0";}
			break;
		}
		t%=10;
		str<<char(t+int('0'));
		place*=10;
	}
	return str;
}

//public

Str::Str()
{
	chr=(char*)malloc(sizeof(char));//new char[1];
	chr[0]='\0';
	strSize=0;
}
Str::~Str()
{
	free(chr);//delete[] chr;
	strSize=0;
	chr=NULL;
}
char* Str::operator!()
{
	return chr;
}
Str& Str::operator=(const Str &str)
{
	set(str.chr);
	return *this;
}
Str& Str::operator=(const char* str)
{
	set(str);
	return *this;
}
Str& Str::operator=(const int val)
{
	toI(val,*this);
	return *this;
}
Str& Str::operator=(const double val)
{
	toD(val,*this);
	return *this;
}
Str& Str::operator=(const char val)
{
	set(val);
	return *this;
}
Str& Str::operator<<(const Str &str)
{
	add(str.chr);
	return *this;
}
Str& Str::operator<<(const char* str)
{
	add(str);
	return *this;
}
Str& Str::operator<<(const int val)
{
	Str t;
	add(t=val);
	return *this;
}
Str& Str::operator<<(const double val)
{
	Str t;
	add(t=val);
	return *this;
}
Str& Str::operator<<(const char val)
{
	add(val);
	return *this;
}

Str& Str::operator-=(const int num)
{
	deleteLeft(num);
	return *this;
}
Str& Str::operator--(const int num)
{
	deleteLeft(1);
	return *this;
}
bool Str::operator==(const Str &str)
{
	return is(str);
}
bool Str::operator==(const char *str)
{
	return is(str);
}
bool Str::operator!=(const Str &str)
{
	return !is(str);
}
bool Str::operator!=(const char *str)
{
	return !is(str);
}
bool Str::is(const char *str)
{
	if (size()!=charSize(str)){return false;}
	int sz=size();
	for (int i=0;i<sz;i++)
	{if (chr[i]!=str[i]){return false;}}
	return true;
}
bool Str::is(const Str &str)
{
	return is(str.chr);
}
void Str::set(const char* str)
{
	int otherSize=charSize(str)+1;
	chr=(char*)calloc(otherSize,sizeof(char));
	for (int i=0;i<otherSize;i++)
	{chr[i]=str[i];}
	recalculateSize();
}
void Str::set(const Str &str)
{
	set(str.chr);
}
void Str::set (const char c)
{
	char str[2];
	str[1]='\0';
	str[0]=c;
	set(str);
}
void Str::add(const char* str)
{
	int otherSize=charSize(str);
	if (otherSize==0){return;}
	int startSize=size();
	int newSize=startSize+otherSize+1;
	chr=(char*)realloc(chr,newSize*sizeof(char));
	for (int i=0;i<otherSize;i++)
	{chr[startSize+i]=str[i];}
	chr[startSize+otherSize]='\0';
	recalculateSize();
}
void Str::add(const Str &str)
{
	add(str.chr);
}
void Str::add(const char c)
{
	char str[2];
	str[1]='\0';
	str[0]=c;
	add(str);
}
void Str::recalculateSize()
{
	strSize=0;
	while (chr[strSize]!='\0'){strSize++;}
}
int Str::size() const
{
	return strSize;
}
void Str::deleteLeft(int num)
{
	if (num<=0){return;}
	int sz=size();
	if (num>=sz){clear();return;}
	int i;
	for (i=0;i<sz-num;i++)
	{
		chr[i]=chr[i+num];
	}
	chr[i]='\0';
	chr=(char*)realloc(chr,(size()+1)*sizeof(char));
	recalculateSize();
}
void Str::deleteRight(int num)
{
	if (num<=0){return;}
	int sz=size();
	if (num>=sz){clear();return;}
	chr[sz-num]='\0';
	chr=(char*)realloc(chr,(size()+1)*sizeof(char));
	recalculateSize();
}
void Str::clear()
{
	chr=(char*)realloc(chr,sizeof(char));
	chr[0]='\0';
	recalculateSize();
}
char Str::getChar(int pos)
{
	if (pos<0||pos>size()){return '\0';}
	return chr[pos];
}

//find commands
int Str::findChar(char c)
{
	for (int i=0;i<size();i++)
	{
		if (chr[i]==c){return i;}
	}
	return -1;
}
int Str::find(const char* str,int lowestSpot)
{
	int sz=charSize(str);
	for (int i=lowestSpot;i<size();i++)
	{
		if (chr[i]==str[0])
		{
			bool good=true;
			for (int ii=1;ii<sz;ii++)
			{
				if (chr[i+ii]!=str[ii]){good=false;ii=sz;}
			}
			if (good){return i;}
		}
	}
	return -1;
}
int Str::find(const char* str)
{
	return find(str,0);
}
int Str::rfind(const char* str)
{
	int sz=charSize(str);
	for (int i=size();i>0;i--)
	{
		if (chr[i]==str[0])
		{
			bool good=true;
			for (int ii=1;ii<sz;ii++)
			{
				if (chr[i+ii]!=str[ii]){good=false;ii=sz;}
			}
			if (good){return i;}
		}
	}
	return -1;
}
int Str::count(char c)
{
	int counter=0;
	for (int i=0;i<size();i++)
	{
		if (chr[i]==c){counter++;}
	}
	return counter;
}
int Str::count(const char* str)
{
	int counter=0;
	int sz=charSize(str);
	for (int i=0;i<size();i++)
	{
		if (chr[i]==str[0])
		{
			bool good=true;
			for (int ii=1;ii<sz;ii++)
			{
				if (chr[i+ii]!=str[ii]){good=false;ii=sz;}
			}
			if (good){counter++;}
		}
	}
	return counter;
}
int Str::replace(const char* thisStr,const char* thatStr,int lowestSpot)
{
	//replace thisStr with thatStr
	int spot=find(thisStr,lowestSpot);
	if (spot==-1){return -1;}
	int sz=size();
	int szb=charSize(thisStr);
	Str before,after;
	before=after=*this;
	before.keep(0,spot);
	if (spot==0){before.clear();}
	after.keep(spot+szb,sz);
	set(before);
	add(thatStr);
	add(after);
	return spot;
}
int Str::replace(const char* thisStr,const char* thatStr)
{
	return replace(thisStr,thatStr,0);
}
int Str::replaceAll(const char* thisStr,const char* thatStr)
{
	int counter=0;
	int sz=charSize(thatStr);
	int spot=0;
	while (1)
	{
		spot=replace(thisStr,thatStr,spot);
		if (spot==-1){return counter;}
		counter++;
		spot+=sz;
	}	
}
int Str::remove(const char* str)
{
	return replace(str,"");
}
int Str::removeAll(const char* str)
{
	return replaceAll(str,"");
}
int Str::keep(int from,int to)
{
	if (to>0){deleteRight(size()-to);}
	else{deleteRight(-to);}
	if (from>=0){*this-=from;}
	else {*this-=size()+from;}
	
	return size();
}
Str& Str::copyPart(Str& Sfrom,int from,int to)
{
	*this=Sfrom;
	keep(from,to);
	return *this;
}
void Str::insert(const char *str,int at)
{
	Str before,after;
	if (at!=0){before.copyPart(*this,0,at);}
	after.copyPart(*this,at,0);
	clear();
	*this<<!before<<str<<!after;
}
void Str::insert(const char str,int at)
{
	char strr[2];
	strr[0]=str;
	strr[1]='\0';
	insert(strr,at);
}
void Str::insert(const Str& str,int at)
{
	insert(str.chr,at);
}
Str& Str::getFromMark(const char *mark, Str &str)
{
	//ex: mark=","
	//get this, and not this
	//but if this happens delete all of self and copy it to str
	
	//always return str
	clear();
	int place;
	place=str.find(mark);
	*this=str;
	if (place==-1)
	{
		str.clear();
		return *this;
	}
	keep(0,place);
	if (place==0){clear();}
	str.keep(place+charSize(mark),0);
	return *this;
}
Str& Str::getFromMark(Str& mark, Str &str)
{
	return getFromMark(mark.chr,str);
}
int Str::fixEdgeFormating(const char *formating)
{
	//removed
	bool loop=true;
	int counter=0;
	int fsz=charSize(formating);
	while (loop)
	{
		loop=false;
		for (int i=0;i<fsz;i++)
		{
			if (chr[0]==formating[i])
			{
				loop=true;
				deleteLeft(1);
				counter++;
			}
		}
	}
	loop=true;
	while (loop)
	{
		loop=false;
		for (int i=0;i<fsz;i++)
		{
			if (chr[size()-1]==formating[i])
			{
				loop=true;
				deleteRight(1);
				counter++;
			}
		}
	}
	return counter;
}
bool Str::deleteChar(int spot)
{
	int sz=size();
	if (spot<0||spot>=sz){return false;}
	if (spot==0){deleteLeft(1);return true;}
	if (spot==sz-1){deleteRight(1);return true;}
	Str a,b;
	a.copyPart(*this,0,spot);
	b.copyPart(*this,spot+1,0);
	set(a);
	add(b);
	return true;
}
bool Str::deleteSection(int from,int to)
{
	int sz=size();
	if (to>sz){return false;}
	if (to<=0){to+=size();}
	if (from<0){from+=size();}
	if (to<=from){return false;}
	Str a,b;
	a.copyPart(*this,0,from);
	b.copyPart(*this,to,0);
	set(a);
	add(b);
	return true;
}
int Str::format(const char *formating)
{
	int sz=size();
	int szb=charSize(formating);
	int count=0;
	bool good;
	for (int i=0;i<sz;i++)
	{
		good=false;
		for (int ii=0;ii<szb;ii++)
		{
			if (chr[i]==formating[ii])
			{
				good=true;
				break;
			}
		}
		if (!good)
		{
			deleteChar(i);
			count++;
			sz--;
			i--;
		}
	}
	return count;
}
int Str::format(const Str &str)
{
	return format(str.chr);
}
bool Str::checkFormat(const char *formating)
{
	int sz=size();
	int szb=charSize(formating);
	bool good;
	for (int i=0;i<sz;i++)
	{
		good=false;
		for (int ii=0;ii<szb;ii++)
		{
			if (chr[i]==formating[ii])
			{
				good=true;
				break;
			}
		}
		if (!good){return false;}
	}
	return true;
}
bool Str::checkFormat(Str &formating)
{
	return checkFormat(formating.chr);
}
int Str::atoi()
{
	Str a,fmt;
	a=*this;
	int findresult=a.find(".");
	if (findresult!=-1)
	{
		a.keep(0,findresult);
	}
	fmt<<STR_NUM<<"-";
	a.format(fmt);
	bool hasNeg=false;
	if (a.chr[0]=='-'){hasNeg=true;}
	a.removeAll("-");
	int sz=a.size();
	int total=0;
	for (int i=0;i<sz;i++)
	{
		total*=10;
		total+=a.chr[i]-(int('0'));
	}
	return total;
}
double Str::atod()
{
	Str a,fmt;
	a=*this;
	fmt="";
	fmt<<STR_NUM<<".-";
	a.format(fmt);
	bool hasNeg=false;
	if (a.chr[0]=='-'){hasNeg=true;}
	a.removeAll("-");
	int got=-1;
	double total=0.0;
	int sz=a.size();
	for (int i=0;i<sz;i++)
	{
		if (a.chr[i]=='.')
		{
			got=10;
			a.removeAll(".");
			sz=a.size();
			i--;
		}
		else if (got==-1)
		{
			total*=10.0;
			total+=(double)(a.chr[i]-(int('0')));
		}
		else
		{
			int num=a.chr[i]-(int('0'));
			total+=((double)num)/((double)got);
			got*=10;
		}
		
	}
	return total;
}
void Str::writeHex(unsigned int val)//hex to string
{
	if (val==0){*this<<"0";return;}
	int sval,startPos=size();
	char c;
	while (val!=0)
	{
		sval=val&0xF;
		val>>=4;
		if (sval<10){c=sval+int('0');}
		else{c=(sval+int('A'))-10;}
		insert(c,startPos);
	}
}
int Str::fromHex()
{
	Str temps;
	temps=*this;
	temps.toLower();
	temps.format("0123456789abcdef");
	int total=0;
	while (temps.size()>0)
	{
		total<<=4;
		if (int(temps.chr[0])>=int('0')&&int(temps.chr[0])<=int('9'))
		{
			total+=int(temps.chr[0])-int('0');
		}
		if (int(temps.chr[0])>=int('a')&&int(temps.chr[0])<=int('f'))
		{
			total+=10+(int(temps.chr[0])-int('a'));
		}
		temps--;
	}
	return total;
}
void Str::toLower()
{
	int sz=size();
	for (int i=0;i<sz;i++)
	{
		if (chr[i]>=int('A')&&chr[i]<=int('Z'))
		{
			chr[i]-=int('A')-int('a');
		}
	}
}
void Str::toUpper()
{
	int sz=size();
	for (int i=0;i<sz;i++)
	{
		if (chr[i]>=int('a')&&chr[i]<=int('z'))
		{
			chr[i]-=int('a')-int('A');
		}
	}
}
void Str::takeFrom(Str &str,int spot)
{
	copyPart(str,0,spot);
	str-=spot;
}
void Str::takeFrom(Str &str,int from,int to)
{
	copyPart(str, from, to);
	deleteSection(from, to);
}
